import { createStore, Commit } from 'vuex'
import axios, { AxiosRequestConfig } from 'axios'
// @ts-ignore
import { arrToObj, objToArr } from 'utils/index'
export interface ResponseType<P = {}> {
    code: number;
    msg: string;
    data: P;
}
export interface UserProps {
    isLogin: boolean;
    nickName?: string;
    _id?: string;
    column?: string;
    email?: string;
    avatar?: ImageProps;
    description?: string;
}
export interface ImageProps {
    _id?: string;
    url?: string;
    createdAt?: string;
    fitUrl?: string;
}
export interface ColumnProps {
    _id: string;
    title: string;
    avatar?: ImageProps;
    description: string;
}
export interface PostProps {
    _id?: string;
    title: string;
    excerpt?: string;
    content?: string;
    image?: ImageProps | string;
    createdAt?: string;
    column: string;
    author?: string | UserProps;
    isHTML?: boolean;
}
interface ListProps<P> {
    [id: string]: P;
}
export interface GlobalErrorProps {
    status: boolean;
    message?: string;
}
export interface GlobalDataProps {
    token: string;
    error: GlobalErrorProps;
    loading: boolean;
    columns: { data: ListProps<ColumnProps>; currentPage: number; total: number };
    posts: { data: ListProps<PostProps>; loadedColumns: string[] };
    user: UserProps;
}
const asyncAndCommit = async(url: string, mutationName: string,
                             commit: Commit, config: AxiosRequestConfig = { method: 'get' }, extraData?: any) => {
    const { data } = await axios(url, config)
    if (extraData) {
        commit(mutationName, { data, extraData })
    } else {
        commit(mutationName, data)
    }
    return data
}
const store = createStore<GlobalDataProps>({
    state: {
        token: localStorage.getItem('token') || '',
        error: { status: false },
        loading: false,
        columns: { data: {}, currentPage: 0, total: 0 },
        posts: { data: {}, loadedColumns: [] },
        user: { isLogin: false }
    },
    mutations: {
        // login(state) {
        //   state.user = { ...state.user, isLogin: true, name: 'viking' }
        // },
        createPost(state, newPost) {
            state.posts.data[newPost._id] = newPost
        },
        fetchColumns(state, rawData) {
            const { data } = state.columns
            const { list, count, currentPage } = rawData.data
            state.columns = {
                data: { ...data, ...arrToObj(list) },
                total: count,
                currentPage: currentPage * 1
            }
        },
        fetchColumn(state, rawData) {
            state.columns.data[rawData.data._id] = rawData.data
        },
        fetchPosts(state, { data: rawData, extraData: columnId }) {
            state.posts.data = { ...state.posts.data, ...arrToObj(rawData.data.list) }
            state.posts.loadedColumns.push(columnId)
        },
        fetchPost(state, rawData) {
            state.posts.data[rawData.data._id] = rawData.data
        },
        deletePost(state, { data }) {
            delete state.posts.data[data._id]
        },
        updatePost(state, { data }) {
            state.posts.data[data._id] = data
        },
        setLoading(state, status) {
            state.loading = status
        },
        setError(state, e: GlobalErrorProps) {
            state.error = e
        },
        fetchCurrentUser(state, rawData) {
            state.user = { isLogin: true, ...rawData.data }
        },
        login(state, rawData) {
            const { token } = rawData.data
            state.token = token
            localStorage.setItem('token', token)
            axios.defaults.headers.common.Authorization = `Bearer ${token}`
        },
        logout(state) {
            state.token = ''
            state.user = { isLogin: false }
            localStorage.remove('token')
            delete axios.defaults.headers.common.Authorization
        }
    },
    actions: {
        fetchColumns({ state, commit }, params = {}) {
            const { currentPage = 1, pageSize = 6 } = params
            // if (!state.columns.isLoaded) {
            //   return asyncAndCommit('/columns', 'fetchColumns', commit)
            // }
            if (state.columns.currentPage < currentPage) {
                return asyncAndCommit(`api/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', commit)
            }
        },
        fetchColumn({ state, commit }, cid) {
            if (!state.columns.data[cid]) {
                return asyncAndCommit(`api/columns/${cid}`, 'fetchColumn', commit)
            }
        },
        fetchPosts({ state, commit }, cid) {
            if (!state.posts.loadedColumns.includes(cid)) {
                return asyncAndCommit(`api/columns/${cid}/posts`, 'fetchPosts', commit, { method: 'get' }, cid)
            }
        },
        fetchPost({ state, commit }, id) {
            const currentPost = state.posts.data[id]
            if (!currentPost || !currentPost.content) {
                return asyncAndCommit(`api/posts/${id}`, 'fetchPost', commit)
            } else {
                return Promise.resolve({ data: currentPost })
            }
        },
        updatePost({ commit }, { id, payload }) {
            return asyncAndCommit(`api/posts/${id}`, 'updatePost', commit, {
                method: 'patch',
                data: payload
            })
        },
        fetchCurrentUser({ commit }) {
            return asyncAndCommit('api/user/current', 'fetchCurrentUser', commit)
        },
        login({ commit }, payload) {
            return asyncAndCommit('api/user/login', 'login', commit, { method: 'post', data: payload })
        },
        createPost({ commit }, payload) {
            return asyncAndCommit('api/posts', 'createPost', commit, { method: 'post', data: payload })
        },
        deletePost({ commit }, id) {
            return asyncAndCommit(`api/posts/${id}`, 'deletePost', commit, { method: 'delete' })
        },
        loginAndFetch({ dispatch }, loginData) {
            return dispatch('login', loginData).then(() => {
                return dispatch('fetchCurrentUser')
            })
        }
    },
    getters: {
        getColumns: (state) => {
            return objToArr(state.columns.data)
        },
        getColumnById: (state) => (id: string) => {
            return state.columns.data[id]
        },
        getPostsByCid: (state) => (cid: string) => {
            return objToArr(state.posts.data).filter((post: { column: string }) => post.column === cid)
        },
        getCurrentPost: (state) => (id: string) => {
            return state.posts.data[id]
        }
    }
})

export default store
